package eu.livotov.jsms.impl;

import eu.livotov.jsms.SMSException;
import eu.livotov.jsms.SMSMessage;
import eu.livotov.jsms.SMSProvider;
import eu.livotov.jsms.util.CryptoTool;
import eu.livotov.jsms.util.XmlTool;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import java.io.*;
import java.net.HttpURLConnection;
import java.net.URL;
import java.text.SimpleDateFormat;
import java.util.UUID;

/**
 * Created with IntelliJ IDEA.
 * User: dlivotov
 * Date: 14.04.12
 * Time: 21:53
 * To change this template use File | Settings | File Templates.
 */
public class GiperMobiProvider implements SMSProvider
{
    private String gmUser;
    private String gmPassword;

    private final static SimpleDateFormat timeStampFormatter = new SimpleDateFormat("yyyyMMddhhmmss");
    private final static String API_ENDPOINT = "https://2kengu.ru/api/message";

    public GiperMobiProvider(final String login, final String password)
    {
        gmUser = CryptoTool.encryptString(login);
        gmPassword = CryptoTool.encryptString(password);
    }

    public String getName()
    {
        return "Giper.Mobi sms provider";
    }

    public SMSMessage sendMessage(SMSMessage sms)
    {
        try
        {
            sms.setId(UUID.randomUUID().toString());

            DocumentBuilderFactory builderFactory = DocumentBuilderFactory.newInstance();
            DocumentBuilder builder = builderFactory.newDocumentBuilder();
            Document requestDoc = builder.newDocument();

            Element root = requestDoc.createElement("message");
            requestDoc.appendChild(root);

            Element login = requestDoc.createElement("login");
            login.setTextContent(CryptoTool.decryptString(gmUser));
            root.appendChild(login);

            Element password = requestDoc.createElement("pwd");
            password.setTextContent(CryptoTool.decryptString(gmPassword));
            root.appendChild(password);

            Element id = requestDoc.createElement("id");
            id.setTextContent(sms.getId());
            root.appendChild(id);

            Element sender = requestDoc.createElement("sender");
            sender.setTextContent(sms.getSender());
            root.appendChild(sender);

            Element text = requestDoc.createElement("text");
            text.setTextContent(sms.getText());
            root.appendChild(text);

            if (sms.getDeliveryDate()!=null && sms.getDeliveryDate().getTime()>System.currentTimeMillis())
            {
                Element time = requestDoc.createElement("time");
                time.setTextContent(timeStampFormatter.format(sms.getDeliveryDate()));
                root.appendChild(time);
            }

            Element phones = requestDoc.createElement("phones");
            root.appendChild(phones);

            for (String num : sms.getNumbers())
            {
                Element phone = requestDoc.createElement("phone");
                phone.setTextContent(num.trim());
                phones.appendChild(phone);
            }

            URL url = new URL(API_ENDPOINT);
            HttpURLConnection huc = (HttpURLConnection) url.openConnection();
            huc.setDoOutput(true);
            huc.setDoInput(true);
            huc.setRequestMethod("POST");
            huc.setRequestProperty("Content-Type", "application/xml");
            OutputStream os = huc.getOutputStream();

            os.write(XmlTool.xmlToString(requestDoc).getBytes("utf-8"));
            os.flush();
            os.close();

            InputStream is = huc.getInputStream();
            InputStreamReader inputstreamreader = new InputStreamReader(is);
            BufferedReader bufferedreader = new BufferedReader(inputstreamreader);
            StringBuffer inString = new StringBuffer();
            String s3;

            while ((s3 = bufferedreader.readLine()) != null)
            {
                inString.append(s3).append("\n");
            }

            bufferedreader.close();
            huc.disconnect();

            DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
            factory.setNamespaceAware(true);
            Document dom = builder.parse(new ByteArrayInputStream(inString.toString().getBytes()));

            NodeList statusNodes = dom.getElementsByTagName("status");
            NodeList statusMessageNodes = dom.getElementsByTagName("message");

            if (statusNodes.getLength() > 0)
            {
                int statusCode = Integer.parseInt(statusNodes.item(0).getTextContent().trim());

                if (statusCode > 0)
                {
                    throw new SMSException(statusCode, describeErrorCode(statusCode) + (statusMessageNodes.getLength() > 0 ? "" + " - " + statusMessageNodes.item(0).getTextContent().trim() : ""));
                }
            }

        } catch (Throwable err)
        {
            err.printStackTrace();
            throw new SMSException(err);
        }

        return sms;
    }

    private String describeErrorCode(final int statusCode)
    {
        switch (statusCode)
        {
            case 1:
                return "Error in request format. Probably mistyped phone number, must be in international format, starting with +";

            case 2:
                return "Invalid giper.mobi authorization credentials. Check username or password";

            case 3:
                return "Your IP address is not allowed to use giper.mobi api.";

            case 4:
                return "Insufficient funds on your giper.mobi account.";

            case 5:
                return "Not allowed sender name in request. Check your registered sender names in your account.";

            case 6:
                return "Message text is blocked by a spam filter";

            case 7:
                return "Incorrect one or more recipient phone number(s).";

            case 8:
                return "Invalid delayed delivery timestamp format.";

            case 9:
                return "Blocked by a spam filter";

            case 10:
                return "Duplicate transaction ID.";

            case 11:
                return "Test mode. Your message is accepted in test mode and was not actually sent to real sms gateway.";

            default:
                return "Undescriped giper.mobi error code: " + statusCode + ", please check the latest API manual.";
        }
    }

}
